/**
 * Created by zaranengap on 2017/8/29.
 *
 * 2018/11/26 ZaraNengap
 * 对于React-router的封装，算是个成功的封装吧
 * 如果你不是来加菜单的，而且没有特别大的需求，不要改这个文件
 * 这个文件对于目前的项目来说很完美的
 *
 */
import React from 'react';
import {getAllMenus} from "share/tools/menu";
import {Router, Route, browserHistory, hashHistory} from 'react-router'
import config from 'config'
import Main from 'containers/main'
import requireAuthentication from 'components/method/requireAuthentication'

import configureStore from 'stores';
import {setCurrentPage} from 'actions/main'
import { getQueryUrlParam } from 'share/common'

// 【不 要 手 动 编 辑 这 个 j s o n】
// 这个json文件使用「https://docs.qq.com/sheet/DVnl4WER1dVpySnhw?tab=BB08J6」编辑并导出excel
// 使用excel/numbers将excel文件转成csv
// 使用「https://csvjson.com/csv2json」将csv转成json
import formCodeList from './formcode-csvjson.json'

const menuIndexUrl = '/main/dashboard';
const menuAdminTenantIndexUrl = '/main/dashboard-admin';
const menuAdminCompanyIndexUrl = '/main/enterprise-manage/org-structure';

/*
* 依次导入目录 src/routes/admin 下面的文件
* 导入的时候，最后与目录下的文件顺序保持一致
* */
//管理员模式下菜单
import basicData from 'routes/admin/basic-data' //基础数据
import budgetSetting from 'routes/admin/budget-setting'  //预算设置
import creditSetting from 'routes/admin/credit-setting'//信用设置
import dashboardAdmin from 'routes/admin/dashboard-admin'  //管理员仪表盘

import enterpriseManage from 'routes/admin/enterprise-manage'; //企业管理
import expenseReimbursementControl from 'routes/admin/expense-reimbursement-control' //费用与报销管控
import financeSetting from 'routes/admin/finance-setting'  //财务设置
import financialAccount from 'routes/admin/financial-account'  //财务核算设置

import helpCenterAdmin from "routes/admin/help-center-admin";  //帮助中心
import incrementService from 'routes/admin/incremment-service' //增值服务
import paySetting from 'routes/admin/pay-setting' //支付设置
import permissionSetting from 'routes/admin/permission-setting' //权限管理

import setting from 'routes/admin/setting'  //基础设置
import supplierManagement from 'routes/admin/supplier-management' //供应商管理
/*
* 依次导入目录 src/routes/normal 下面的文件
* */
//非管理员模式下菜单
import approve from 'routes/normal/approve'  //审批
import bookingManagement from 'routes/normal/booking-management' //订票

import budget from 'routes/normal/budget'  //预算
import credit from 'routes/normal/credit' //信用
import dashboard from 'routes/normal/dashboard'  //仪表盘

import dataCenter from 'routes/normal/data-center' //数据中心
import scanReceive from 'routes/normal/scan-receive' //扫码收单
import expenseReport from 'routes/normal/expense-report'  //报销单
import financialManagement from 'routes/normal/finacial-management'  //财务管理
import helpCenterUser from 'routes/normal/help-center-user' //帮助中心-普通用户模式

import loanBilling from 'routes/normal/loan-billing'  //借款及还款
import messagesCenter from 'routes/normal/messages-center' //消息中心
import mileageSubsidyExpense from 'routes/normal/mileage-subsidy-expense' //里程补贴
import myAccount from 'routes/normal/my-account'  //我的账本

// import myAgency from 'routes/normal/my-agency'  //我的代理
import pay from 'routes/normal/pay'  //支付
import personalSettings from 'routes/normal/personal-settings' //个人设置
import reportDistribution from 'routes/normal/report-distribution'  //报表分配

import reportList from 'routes/normal/report-list' //报表
import request from 'routes/normal/request'  //申请单
import requestClose from 'routes/normal/request-close'  //申请单关闭
import subApplicationView from 'routes/normal/sub-application-view'  //子应用
import greenCode from 'routes/normal/green-code'  // 健康码申请
import businessAndGiftApplication from 'routes/normal/business-and-gift-application' // 商务及礼品申请
import publicServiceCardApplication from 'routes/normal/public-service-card-application' // 公务卡申请
import agencyApplication from 'routes/normal/agency-application' // 公务卡申请
import otherApplication from 'routes/normal/other-application' // 其他事项申请单

import thirdConsumption from 'routes/normal/third-consumption'  //第三方消费
import myFlightOrder from 'routes/normal/my-flight-order'  // 我的机票
import myHotelOrder from 'routes/normal/my-hotel-order'  // 我的酒店
import contract from 'routes/normal/contract'; // 我的合同
import componentLib from 'routes/normal/component-lib';

import customerInfoMaintenance from 'routes/normal/customer-info-maintenance'
import supplierMaintenance from 'routes/normal/supplier-maintenance'

import todo from 'routes/normal/todo'
import done from 'routes/normal/done'
import myTravel from 'routes/normal/my-travel'
import applications from 'routes/normal/applications'
import consumptions from 'routes/normal/consumptions'
import union from 'routes/normal/union'
import { message } from 'antd';

/**
 * 项目菜单整体路由配置
 * 分为三层: menuItem, subMenuItem, children
 * menuItem为菜单一级
 * subMenuItem为菜单二级
 * children为具体页面的所有内部页面
 * @params name    菜单标题
 * @params key    菜单id
 * @params url    菜单路径
 * @params components    菜单组件
 * @params parent    父菜单id
 * @params subMenu    二级菜单列表
 * @params children    页面内部所有页面 key : page
 * @params admin    bool:代表管理员模式
 * @params company  bool:-公司模式下是否显示，如果该值与tenant都不设置，则都显示
 * @params tenant   bool:-集团模式下是否显示，如果该值与company都不设置，则都显示
 * @params role     array-string:在该角色权限下显示，都有才会显示，如果不设置则不控制，可以为字符串或数组
 * @params hasRole  array:-在该角色数组权限下显示，如果有其中之一即显示，不设置则不控制
 * @params pageRole array:-在该角色数组权限下显示，如果有其中之一即显示，不设置则不控制
 * @params oldCompany  string:是否只在老公司下显示，'OLD_ONLY'为只在老公司下显示，'NEW_ONLY'为老公司不显示，不设置则都显示
 * @params hideInUrl  string: 在包含该域名的情况下隐藏
 */
const menu = [
  dashboard,  //仪表盘
  todo, // 待办事项
  done, // 待办事项
  myTravel,// 我的出行
  consumptions, // 消费记录

  myAccount,  //我的账本
  expenseReport,  //报销单

  union, // 工会
  greenCode, // 健康码申请

  // request,  //申请单
  requestClose,  //申请单关闭
  applications,
  // businessAndGiftApplication, // 商务及礼品申请单
  // publicServiceCardApplication, // 公务卡申请
  // agencyApplication, // 代理申请单
  // otherApplication, // 其他事项申请单
  loanBilling, //借款及还款
  // myAgency, //我的代理
  // approve, //审批
  subApplicationView, //子应用
  thirdConsumption,  //第三方消费
  // myFlightOrder,  //我的机票
  // myHotelOrder,  //我的酒店
  financialManagement,  //财务管理
  budget,  //预算
  pay,  //支付
  bookingManagement,//订票
  mileageSubsidyExpense,//里程补贴
  reportDistribution,   //报表分配
  dataCenter, //数据中心
  scanReceive, //扫码收单
  messagesCenter,//消息中心
  reportList, //报表
  credit,  //信用
  helpCenterUser,//帮助中心-员工模式
  personalSettings,  //个人设置
  componentLib, //组件库
  contract, //合同
  customerInfoMaintenance,//客户主体业务数据
  supplierMaintenance,//供应商维护
    /** 以下是管理员模式下的菜单 **/
  dashboardAdmin,  //管理员仪表盘
  setting,  //基础设置
  expenseReimbursementControl, //费用与报销管控
  budgetSetting,  //预算设置
  financeSetting,  //财务设置
  financialAccount, //财务核算设置
  basicData,      //基础数据
  enterpriseManage,  //企业管理
  paySetting,   //支付设置
  creditSetting,  //信用设置
  supplierManagement, //供应商管理
  helpCenterAdmin,//帮助中心
  incrementService,//增值服务
  permissionSetting,//权限管理
];
if (config.appEnv !== 'dist') {
  // getAllMenus(menu);
}
const supportBrowserHistory = typeof history.pushState !== 'undefined';

/**
 * 渲染二级菜单页内的children
 * @param subItem
 * @return {Array}
 */
const renderSubItem = (subItem) => {
  let result = [];
  if (subItem.children) {
    for (let childName in subItem.children) {
      const item = subItem.children[childName]
      // console.log(`routes mount ${item.url}`)
      result.push(
        <Route key={item.key} path={item.url} component={item.components}/>
      )
    }
    return result
  }
};

/**
 * 整个项目的路由配置，配置在项目入口可使每个页面可以单独进入
 */
const getClientRoute = (targetMenu = menu) => (
  <Route path={menuIndexUrl} component={requireAuthentication(Main)}>
    {targetMenu.map(item => {

      const routes = item.subMenu ? item.subMenu.map(subItem =>
        <Route key={subItem.key} path={subItem.url} component={subItem.components}>
          {renderSubItem(subItem)}
        </Route>
      ) : []

      // 这里是不得已而为之，原来的设计没考虑既有subMenu又有children，默认只有subMenu里面的
      // page有children。所以原来的设计先判断subMenu，有了就忽略了children的情况。
      // 而为了支持菜单调整的需求，现在需要既有subMenu又有children，那就要求item.components的
      // render方法里加上 {props.children} 或者 children不放到item.components里，而是作为单独
      // 的Route
      // 目前选择后者。
      if (item.children) {
        for (const childName in item.children) {
          const subItem = item.children[childName]
          routes.push(
            <Route key={subItem.key} path={subItem.url} component={subItem.components}>
              {renderSubItem(subItem)}
            </Route>
          )
        }
      } else {
        routes.unshift(
          <Route key={item.key} path={item.url} component={item.components}></Route>
        )
      }

      return routes
    })}
  </Route>
);

function getChildrenList() {
  let result = [];
  menu.map(item => {
    item.subMenu ? item.subMenu.map(subItem => {
      if (subItem.children) {
        for (let child in subItem.children)
          result.push(subItem.children[child])
      }
    }) : (
      item.children ? Object.keys(item.children).map(key => {
        result.push(item.children[key])
      }) : {}
    );
  });
  return result;
}

/**
 * 首页菜单的路由配置，配置后台主要的路由层级
 */
const getMainRoute = (targetMenu = menu) => {
  const list = getMenuList().concat(getChildrenList(targetMenu))
  console.log('routelist', list)
  return (
    <Router history={supportBrowserHistory ? browserHistory : hashHistory} onUpdate={updateCurrentPage}>
      {
        list.map(targetItem =>
          <Route key={targetItem.key} path={targetItem.url} component={targetItem.components}/>)
      }
    </Router>
  );
}

function getMenuList() {
  let result = [];
  for (const item of menu) {
    if (item.subMenu) {
      result = result.concat(item.subMenu)
      if (item.children) {
        result = result.concat(Object.values(item.children))
      }
    } else {
      if (item.children) {
        result = result.concat(Object.values(item.children))
      }
      result.push(item)
    }
  }
  return result;
}

/**
 * 根据传入的值和值名称查找菜单项
 * @param attr    值
 * @param attrName    值名称
 * @return {*}    菜单项
 */
function getMenuItemByAttr(attr, attrName) {
  let current = null;
  this.menu.map(menuItem => {
    if (menuItem[attrName] === attr)
      current = menuItem;
    else {
      if (menuItem.subMenu) {
        menuItem.subMenu.map(subMenuItem => {
          if (subMenuItem[attrName] === attr)
            current = subMenuItem;
          if (subMenuItem.children) {
            for (let child in subMenuItem.children)
              if (subMenuItem.children[child][attrName] === attr)
                current = subMenuItem;
          }
        })
      }
      if (menuItem.children) {
        for (let child in menuItem.children)
          if (menuItem.children[child][attrName] === attr)
            current = menuItem;
      }
    }
  });
  return current;
}

/**
 * 更新当前页面currentPage到Redux
 */
const updateCurrentPage = () => {
  updateCurrentPageFun();
};

function updateCurrentPageFun (){
  let path = supportBrowserHistory ? location.pathname : location.hash;
  if (path.indexOf('?') > -1)
    path = path.substr(0, path.indexOf('?'));
  let nowCurrent = [];
  let sections = path.split('/');
  sections.splice(0, 1);
  sections.map(section => {
    let routeItem = menuRoute.getRouteItem(section, 'key');
    routeItem !== null && nowCurrent.push(routeItem);
  });
  configureStore.store.dispatch(setCurrentPage(nowCurrent))
}

/**
 * @wanning 如果一个页面出现在多个subMenu中，这个方法其实就有问题了，
 * 用户在页面A下想要跳转到页面B，但是页面B同时存在在A下面和C下面，那就可能拿到C下面
 * 的B（只要C比A早定义）。
 *
 * 而getRouteItem用到的地方很多，全县那边
 *
 *
 * 根据传入的值和值名称查找页面项（包括subMenu和children在内的）
 * @param attr    值
 * @param attrName    值名称
 * @return {*}    页面项
 */
function getRouteItem(attr, attrName = 'key') {

  function recur(menuMap){
    for (const key in menuMap) {
      const current = menuMap[key]
      if (current[attrName] === attr) {
        return current
      }

      if (current.children) {
        const subResult = recur(current.children)
        if (subResult) {
          return subResult
        }
      }

      if (current.subMenu) {
        const subResult = recur(current.subMenu)
        if (subResult) {
          return subResult
        }
      }
    }
    return null
  }

  return recur(this.menu)

}

function getPageUrlByKey(key){
  console.log(`getPageUrlByKey: ${key}`)
  switch(key) {
    case 'configuration-center':
      return '/main/setting/configuration-center'
    default:
      return ''
  }
}

/**
 * 通用返回方法
 * 机制：
 * 如果当前组件有backType==='history'，直接history返回（适用于back-btn组件）
 *
 *
 *
 *
 * @param {*} $this
 */
function goBack($this){
  if ($this.props.backType === 'history') {
    window.history.go(-1);
    return
  }
  let backUrlKey = $this.props.backUrlKey || getQueryUrlParam('backUrlKey')
  if (!backUrlKey) {
    let index = 2
    const pathname = $this.props.location? $this.props.location.pathname : location.pathname
    while(true) {
      console.log($this.context.router)
      const backUrlKey = pathname.split('/')[index]
      if (!backUrlKey) {
        break
      }
      const routeItem = menuRoute.getRouteItem(backUrlKey)
      if (backUrlKey && backUrlKey.url) {
        break
      } else {
        index++
      }
    }
  }

  if (backUrlKey) {
    const routeItem = menuRoute.getRouteItem(backUrlKey)
    if (routeItem && $this.context.router) {
      $this.context.router.push(routeItem.url)
      return
    }
  }

  window.history.go(-1);
}

const formCodeMetadata = {}

/**
 * 通用到跳转表单相关界面的方法，目前只处理申请单和报销单
 * @param {React.Component} $this
 * @param {string} formCode
 * @param {{
 *   action: "new"|"edit"|"detail" // 操作类型，默认detail，注意不是每种表单都有这3个aciton
 *   backUrlKey: string // 返回的key；默认会从$this.props.location.query里取，
 *   params: { // 路由参数替换，id会替换:id, applicationOID会替换:applicationOID
 *    [x:string]: string
 *   },
 * }} options
 *
 * @example
 * menuRoute.goForm(this, 'SQ002', {
 *  action: 'detail',
 *  params: {
 *    applicationOID: "123123123-123123-123123-12312"
 *  }
 * })
 */
function goForm($this, formCode, options = {}){
  const formItem = formCodeList.find(item => item.formCode === formCode)
  if (!formItem) {
    message.error(`跳转失败，未识别该表单编码（${formCode}）`)
    console.error('[DEBUG] 跳转失败',{formCode, options})
    return
  }

  const formType = formItem.applicationFormType
  const isGiftDetail = formItem['申请单详情页特殊处理（默认/礼品）'] === '礼品'
  const isRequest = formType < 7 || formType === 9
  const isExpenseReport = formType >=7 && formType <= 8
  if (formType > 9) {
    message.error('跳转失败，该表单不是申请单或报销单')
    console.error('[DEBUG] 跳转失败',{formCode, options})
    return
  }
  const action = options.action || 'detail'
  const backUrlKey = options.backUrlKey || $this.props.backUrlKey || getQueryUrlParam('backUrlKey')
  const params = options.params || {}
  let url = ''
  let key = ''
  let baseKey = [
    '', // 0 无
    'travel-and-booking', // 1 出行及预订
    'business-and-gift-application', // 2 商务应酬及礼品
    'public-service-card-application', // 3 公务卡申请
    'other-application', // 4 特殊事项申请
    'agency-application', // 5 代理申请
    'union-request', // 6 工会申请单
    'expense-report', // 7 报销单
    'union-expense-report', // 8 工会报销单
    'green-code-request', // 9 健康码
  ][formType]
  if (isExpenseReport) {
    if (action === 'detail') {
      key = `${baseKey}-detail`
    } else if (action === 'new') {
      key = `new-${baseKey}`
    }
  } else if (isRequest) {
    if (action === 'detail') {
      if (isGiftDetail) {
        key = `${baseKey}-giftDetail`
      } else {
        key = `${baseKey}-detail`
      }
    } else if (action === 'new') {
      key = `new-${baseKey}`
    } else if (action === 'edit') {
      // 特殊处理
      if (isGiftDetail) {
        key = `${baseKey}-giftDetail`
      } else {
        key = `${baseKey}-edit`
      }
    }
  }
  // console.log(`[DEBUG]${formCode}跳转到 ${key}`)
  try {
    url = menuRoute.getRouteItem(key).url
  } catch(e){
    message.error(`跳转失败，未定义的路由（${key}）`)
    console.error('[DEBUG] 跳转失败，未定义的路由',key, formItem)
  }

  for (const key of Object.keys(params))  {
    url = url.replace(`:${key}`, params[key])
  }

  if (backUrlKey) {
    url += `?backUrlKey=${backUrlKey}`
  }

  console.log('[DEBUG] 跳转成功', url, formCode, options)
  if (options.needOpen) {
    window.open(url);
  } else {
    $this.context.router.push(url)
  }
}

const menuRoute = {
    indexUrl: menuIndexUrl,
    adminTenantIndexUrl: menuAdminTenantIndexUrl,
    adminCompanyIndexUrl: menuAdminCompanyIndexUrl,
    getClientRoute,
    getMainRoute,
    menu: menu,
    getMenuItemByAttr: getMenuItemByAttr,
    getRouteItem: getRouteItem,
    updateCurrentPageFun,
    getPageUrlByKey,
    goBack,
    goForm,
};

export default menuRoute
